package com.lincoln.framework.controller;

import com.lincoln.framework.common.Constant;
import com.lincoln.framework.bean.QueryInfo;
import com.lincoln.framework.common.MessageHandlerEx;
import com.lincoln.framework.common.WebUtils;
import com.lincoln.framework.hibernate.Page;
import com.lincoln.framework.utils.QueryUtils;
import com.lincoln.framework.utils.ValidateCodeUtils;
import com.lincoln.framework.utils.qrcode.QRcodeUtils;
import com.lincoln.framework.utils.FrameworkLogger;
import com.lincoln.framework.utils.ParameterChecker;
import com.lincoln.framework.utils.StringUtilsEx;
import com.lincoln.framework.utils.WebParamUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

/**
 * controller基础类，处理一些通用方法
 * 
 * @author zwm
 * 
 * @version 2016-2-25 上午11:04:13
 */
public abstract class BaseController<T> {

	/**
	 * 日志
	 */
	public static FrameworkLogger logger = FrameworkLogger.initFrameworkLogger(BaseController.class);

	/**
	 * 标志使用那个字段进行排序
	 */
	protected String orderBy;

	/**
	 * 标志排序类型
	 */
	protected String order;

	/**
	 * 当前操作查询页码,分页需要该变量
	 */
	protected int pageNo = 0;

	/**
	 * 是否返回查询,自动返回列表页面，使用该变量
	 */
	protected int isBack;

	/**
	 * 分页查询结果对象，页面通过访问该变量获取查询结果数据
	 */
	private Page<T> resultPage;

	/**
	 * 枚举查询类型，区分系统支持的查询操作类型。
	 */
	protected enum QueryType {
		FORM_QUERY, PAGE_QUERY, ORDER_QUERY, BACK_QUERY
	}

	/**
	 * 返回参数列表
	 */
	private Map<String, Object> ajaxAttributes = new HashMap<String, Object>();

	/**
	 * ajax消息处理工具类
	 */
	private MessageHandlerEx messageHandlerEx;
	
	/** 地区 */
	private String region;

	/** 是否默认初始化地区 */
	private int isDefault;

	/** 显示级别 */
	private int level;
	
	/**
	 * 跳转文章详情页
	 */
	@RequestMapping("/toArticleDetail.do")
	public String toArticleDetail(HttpServletRequest request) {
		int id = WebParamUtils.getIntParameter(request, "id");
		String type = request.getParameter("type");
		if (ParameterChecker.isNullOrEmpty(type)) {
			type = "article";
		}
		String serverName = request.getServerName();
		if (request.getRequestURI().toString().startsWith("/mobile/")) {
			serverName += "/mobile";
		}
		return "redirect:"
				+ WebUtils.operateJsessionidOfUrl("http://" + serverName + "/information/toDetail.htm?type=" + type
						+ "&id=" + id);
	}

	/**
	 * 返回原页面跳转
	 * 
	 * @desc: 该方法将session中保存的最近一次查询条件取出并进行列表页面地址跳转
	 * @return String
	 * @throws Exception
	 */
	@RequestMapping("/backList.do")
	@ResponseBody
	public void backList() throws Exception {
		String className = this.getClass().getName();

		HttpServletRequest request = this.getRequest();
		HttpSession session = request.getSession();
		HttpServletResponse response = this.getResponse();

		String redirectListPath = (String) session.getAttribute(className + "[listPath]");
		// 如果之前没有显式保存过返回地址，就默认返回toList方法。
		if (redirectListPath == null) {
			redirectListPath = request.getRequestURI().replace("/backList", "/toList");
		}
		response.sendRedirect(redirectListPath + "?isBack=1");
	}
	
	/**
	 * 获取二维码图片地址
	 */
	@RequestMapping("/getQrcodeUrl.do")
	@ResponseBody
	public String getQrcodeUrl(HttpServletRequest request) {
		String content = WebParamUtils.getParameter(request, "content");
		try {
			if (!ParameterChecker.isNullOrEmpty(content)) {
				QRcodeUtils.image(getResponse(), content, 100);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}
	
	/**
	 * 获取二维码图片地址
	 */
	@RequestMapping("/downloadQrcodeUrl.do")
	@ResponseBody
	public String downloadQrcodeUrl(HttpServletRequest request) {
		String content = WebParamUtils.getParameter(request, "content");
		try {
			if (!ParameterChecker.isNullOrEmpty(content)) {
				QRcodeUtils.download(getResponse(), "qrcode_for_" + StringUtilsEx.MD5(content) + ".png" , content, 300);
			}
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 保存当前请求查询的字符串
	 * 
	 * @throws UnsupportedEncodingException
	 */
	protected void saveRequestParameter() {
		String className = this.getClass().getName();

		HttpServletRequest request = this.getRequest();
		String redirectURI = request.getRequestURI();

		request.getSession().setAttribute(className + "[listPath]", redirectURI);
	}

	/**
	 * 保存查询信息，并且返回保存查询参数的分页对象,可自定义排序字段
	 */
	protected Page<T> saveQueryInfoAndReturnPage(String defaultOrder, String defaultOrderBy) {
		Page<T> page = this.saveQueryInfoAndReturnPage();
		if (ParameterChecker.isNullOrEmpty(page.getOrderBy())) {
			page.setOrder(defaultOrder);
			page.setOrderBy(defaultOrderBy);
		}
		return page;
	}

	/**
	 * 保存查询信息，并且返回保存查询参数的分页对象,不设置查询排序方法。
	 */
	protected Page<T> saveQueryInfoAndReturnPage() {
		this.saveRequestParameter();

		if (!ParameterChecker.isNullOrEmpty(this.getRequest().getParameter("isBack"))) {
			isBack = Integer.valueOf(this.getRequest().getParameter("isBack"));
		}
		if (!ParameterChecker.isNullOrEmpty(this.getRequest().getParameter("pageNo"))) {
			pageNo = Integer.valueOf(this.getRequest().getParameter("pageNo"));
		}
		if (!ParameterChecker.isNullOrEmpty(this.getRequest().getParameter("order"))) {
			order = this.getRequest().getParameter("order");
		}
		if (!ParameterChecker.isNullOrEmpty(this.getRequest().getParameter("orderBy"))) {
			orderBy = this.getRequest().getParameter("orderBy");
		}
		resultPage = new Page<T>(this.getCountPerPage(), true);
		QueryInfo info = this.saveQueryInfo();
		resultPage.setOrder(info.getOrder());
		resultPage.setOrderBy(info.getOrderBy());
		resultPage.setPageNo(info.getPageNo());
		Map<String, String> tm = info.getRequestParamMap();
		if (tm != null) {
			Set<Entry<String, String>> set = tm.entrySet();
			for (Entry<String, String> e : set) {
				resultPage.addQueryParam(e.getKey(), e.getValue());
			}
		}
		return resultPage;
	}

	/**
	 * 保存当前请求查询的字符串
	 */
	private QueryInfo saveQueryInfo() {
		QueryInfo queryInfo = QueryUtils.getQueryInfoFromSession(this.getRequest(), this.getClass().getName());

		switch (this.getQueryType()) {
		case FORM_QUERY:
			queryInfo.setPageNo(1);
			Map<String, String> requestParamMap = createParameterMapFromRequest();
			queryInfo.setRequestParamMap(requestParamMap);
			break;
		case PAGE_QUERY:
			queryInfo.setPageNo(pageNo);
			break;
		case ORDER_QUERY:
			queryInfo.setOrderBy(orderBy);
			queryInfo.setOrder(order);
			break;
		case BACK_QUERY:
			break;
		default:
			throw new RuntimeException("非法的查询类型");
		}

		this.setSearchParamsBackRequest(queryInfo);
		return queryInfo;
	}

	/**
	 * 将request对象中的参数map转化成标准的map对象,checkbox多个提交参数的情况，使用,分割values
	 */
	private Map<String, String> createParameterMapFromRequest() {
		Map<String, String> map = new HashMap<String, String>();
		HttpServletRequest request = this.getRequest();
		Set<Entry<String, String[]>> set = (Set<Entry<String, String[]>>) request.getParameterMap().entrySet();
		for (Entry<String, String[]> p : set) {
			String key = p.getKey().toString();
			String[] values = p.getValue();
			String valueStr = "";
			for (int i = 0, len = values.length; i < len; i++) {
				valueStr += values[i];
				if (len != (i + 1)) {
					valueStr += ",";
				}
			}
			map.put(key, valueStr);
		}
		return map;
	}

	/**
	 * 将请求参数重新配置会request对象，提供页面使用jstl进行获取的能力
	 */
	private void setSearchParamsBackRequest(QueryInfo queryInfo) {
		HttpServletRequest request = this.getRequest();
		Map<String, String> tm = queryInfo.getRequestParamMap();
		if (tm != null) {
			Set<Entry<String, String>> set = tm.entrySet();
			for (Entry<String, String> e : set) {
				request.setAttribute(e.getKey(), e.getValue());
			}
		}
	}

	/**
	 * 根据分页相关变量，判断当前查询类型
	 */
	private QueryType getQueryType() {
		HttpServletRequest request = this.getRequest();
		if (!ParameterChecker.isNullOrEmpty(request.getParameter("isBack"))) {
			return QueryType.BACK_QUERY;
		}
		if (!ParameterChecker.isNullOrEmpty(request.getParameter("pageNo"))) {
			return QueryType.PAGE_QUERY;
		}
		if (!ParameterChecker.isNullOrEmpty(request.getParameter("order"))
				&& !ParameterChecker.isNullOrEmpty(request.getParameter("orderBy"))) {
			return QueryType.ORDER_QUERY;
		}
		return QueryType.FORM_QUERY;
	}

	/**
	 * 绕过Template,直接输出验证码(image/jpeg)
	 */
	protected String renderValidateImg(String sessionKey) {
		try {
			HttpServletRequest request = this.getRequest();
			HttpServletResponse response = this.getResponse();

			String code = ValidateCodeUtils.getInstance().getRandomString();
			request.getSession().setAttribute(sessionKey, code);

			response.setContentType("image/jpeg");
			response.setHeader("Pragma", "no-cache");
			response.setHeader("Cache-Control", "no-cache");
			response.setDateHeader("Expires", 0);
			OutputStream outputStream = response.getOutputStream();
			ValidateCodeUtils.getInstance().string2img(code, outputStream);
			outputStream.flush();
			outputStream.close();
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}

	/**
	 * 获取上下文HttpServletRequest
	 */
	protected HttpServletRequest getRequest() {
		RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
		return ((ServletRequestAttributes) attributes).getRequest();
	}

	/**
	 * 获取上下文HttpServletResponse
	 */
	protected HttpServletResponse getResponse() {
		RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
		return ((ServletRequestAttributes) attributes).getResponse();
	}

	/**
	 * 根据key查询request中的cookie
	 * 
	 * @param key
	 * @return Cookie
	 */
	protected Cookie getCookie(String key) {
		HttpServletRequest request = this.getRequest();
		Cookie[] cookies = request.getCookies();
		if (cookies != null && cookies.length > 0) {
			for (Cookie cookie : cookies) {
				if (cookie.getName().equals(key)) {
					return cookie;
				}
			}
		}
		return null;
	}

	/**
	 * 设置参数
	 * 
	 * @param name
	 * @param obj
	 */
	protected void setAttributes(String name, Object obj) {
		ajaxAttributes.put(name, obj);
	}

	/**
	 * 返回正确信息
	 */
	protected void returnSuccess() {
		this.returnData("", false);
	}

	/**
	 * 返回正确信息
	 * 
	 * @param msg
	 */
	protected void returnSuccess(String msg) {
		this.returnData(msg, false);
	}

	/**
	 * 返回错误信息
	 * 
	 * @param msg
	 */
	protected void returnError(String msg) {
		this.returnData(msg, true);
	}

	/**
	 * 返回错误信息并刷新
	 */
	protected void returnError(String msg, boolean refresh) {
		if (refresh) {
			this.setAttributes("refresh", true);
		}
		this.returnError(msg);
	}

	/**
	 * 返回错误信息
	 * 
	 * @param msg
	 * @param hasError
	 */
	private void returnData(String msg, boolean hasError) {
		this.messageHandlerEx = MessageHandlerEx.instance(this.getRequest(), this.getResponse());
		if (hasError) {
			this.messageHandlerEx.ajaxErrorReturn(msg, ajaxAttributes);
		} else {
			this.messageHandlerEx.ajaxSuccessReturn(msg, ajaxAttributes);
		}
	}
	
	public String getRegion(HttpServletRequest request) {
		return request.getParameter("chineseRegion");
	}

	public int getIsDefault(HttpServletRequest request) {
		return WebParamUtils.getIntParameter(request, "isDefault");
	}

	public int getLevel(HttpServletRequest request) {
		return WebParamUtils.getIntParameter(request, "level");
	}

	/**
	 * 设置分页对象每页查询的条数，默认为系统统一设置Const.PAGE_COUNT，有些查询不需要进行分页 可重写该方法返回Integer.MAX_VALUE。
	 */
	protected int getCountPerPage() {
		return Constant.PAGE_COUNT;
	}

	public String getOrderBy() {
		return orderBy;
	}

	public void setOrderBy(String orderBy) {
		this.orderBy = orderBy;
	}

	public String getOrder() {
		return order;
	}

	public void setOrder(String order) {
		this.order = order;
	}

	public int getPageNo() {
		return pageNo;
	}

	public void setPageNo(int pageNo) {
		this.pageNo = pageNo;
	}

	public int getIsBack() {
		return isBack;
	}

	public void setIsBack(int isBack) {
		this.isBack = isBack;
	}

	public Page<T> getResultPage() {
		return resultPage;
	}

	public void setResultPage(Page<T> resultPage) {
		this.resultPage = resultPage;
	}
}
